package org.openmrs.module.simplelabentry.web.controller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.openmrs.Concept;
import org.openmrs.ConceptAnswer;
import org.openmrs.ConceptSet;
import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.openmrs.module.hospitalcore.LabService;
import org.openmrs.module.hospitalcore.model.Lab;
import org.openmrs.module.hospitalcore.model.LabTest;
import org.openmrs.module.hospitalcore.util.HospitalCoreConstants;
import org.openmrs.module.simplelabentry.SimpleLabEntryService;
import org.openmrs.module.simplelabentry.util.DateUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller("SimpleLabentryPrintWorkListController")
@RequestMapping("/module/simplelabentry/printWorkList.form")
public class PrintWorkListController {

	@RequestMapping(method = RequestMethod.GET)
	public String printWorklist(
			@RequestParam(value = "orderDate", required = false) String orderDateParam,
			@RequestParam(value = "labName", required = false) String labName,
			HttpServletRequest request, Model model) {
		ServletContext sc = request.getSession().getServletContext();

		SimpleLabEntryService sls = Context
				.getService(SimpleLabEntryService.class);
		Lab lab = sls.getCurrentLab();
		LabService ls = Context.getService(LabService.class);
		Date orderDate;
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
			orderDate = sdf.parse(orderDateParam);
		} catch (ParseException e) {
			e.printStackTrace();
			return "/module/simplelabentry/printWorkList";
		}

		List<LabTest> labTests = ls.getLabTestByDateAndStatus(lab, orderDate,
				HospitalCoreConstants.LABTEST_STATUS_ACCEPTED);

		// get the family concept id
		System.out
				.println("========= PrintWorkListController.java.printWorklist =========");
		Concept conceptLab = Context.getConceptService().getConcept(labName);

		if (conceptLab != null) {
			String conceptIdFamilyName = "labentry.familyid." + labName;
			Set<Integer> familyIDs = (Set<Integer>) sc
					.getAttribute(conceptIdFamilyName);
			System.out.println("familyIDs ==> " + familyIDs);
			if (familyIDs == null) {
				familyIDs = new HashSet<Integer>();
				getConceptIDFamily(familyIDs, conceptLab);
				sc.setAttribute(conceptIdFamilyName, familyIDs);
				System.out.println("new familyIDs ==> " + familyIDs);
			}

			// filter the labTest
			System.out.println("labTests before filtering ==> "
					+ labTests.size());
			List<LabTest> filteredLabTests = new ArrayList<LabTest>();
			for (LabTest lt : labTests) {
				if (familyIDs.contains((lt.getOrder().getConcept().getId()))) {
					System.out.println("Inserted test ==> "
							+ lt.getOrder().getConcept().getId());
					filteredLabTests.add(lt);
				}
			}
			System.out.println("labTests after filtering ==> "
					+ filteredLabTests.size());
			
			generateLabTests(filteredLabTests);

			// print it
			model.addAttribute("labTests", filteredLabTests);
			List<Map<String, String>> dataSet = new ArrayList<Map<String, String>>();
			for (LabTest lt : filteredLabTests) {
				Map<String, String> row = new HashMap<String, String>();
				row.put("orderDate", DateUtil.formatDate(lt.getOrder()
						.getDateCreated(), "dd/MM/yyyy"));
				row.put("patientIdentifier", lt.getOrder().getPatient()
						.getPatientIdentifier().getIdentifier());
				row.put("lab", labName);
				row.put("name", getFullName(lt.getOrder().getPatient()));
				row.put("age",
						DateUtil.getTimespan(new Date(), lt.getOrder()
								.getPatient().getBirthdate()));
				row.put("gender", lt.getOrder().getPatient().getGender());
				row.put("testName", lt.getOrder().getConcept().getName().getShortName()
						.isEmpty() ? lt.getOrder().getConcept().getName().getName() : lt.getOrder().getConcept()
						.getName().getShortName());
				
				row.put("sampleNo", lt.getSampleNumber());
				row.put("enterResult", "");
				dataSet.add(row);
			}

			model.addAttribute("dataSet", dataSet);
		}

		return "/module/simplelabentry/printWorkList";
	}

	// Get the fullname of a patient
	private String getFullName(Patient patient) {
		String fullName = "";

		if (!StringUtils.isBlank(patient.getGivenName())) {
			fullName += patient.getGivenName() + " ";
		}

		if (!StringUtils.isBlank(patient.getMiddleName())) {
			fullName += patient.getMiddleName() + " ";
		}

		if (!StringUtils.isBlank(patient.getFamilyName())) {
			fullName += patient.getFamilyName();
		}

		fullName = StringUtils.trim(fullName);
		return fullName;
	}

	@RequestMapping(method = RequestMethod.POST)
	public String showWorklist() {
		System.out.println("abc");
		return "/module/simplelabentry/printWorkList";
	}

	/**
	 * Get all the IDs of concepts that are children of a given concept
	 * 
	 * @param concept
	 * @return set of IDs
	 */
	private void getConceptIDFamily(Set<Integer> family, Concept concept) {
		if ((concept.getConceptClass().getName().equals("Test"))
				|| (concept.getConceptClass().getName().equals("LabSet"))) {
			family.add(concept.getConceptId());
		} else {

			for (ConceptAnswer ca : concept.getAnswers()) {
				Concept c = ca.getAnswerConcept();
				getConceptIDFamily(family, c);
			}

			for (ConceptSet cs : concept.getConceptSets()) {
				Concept c = cs.getConcept();
				getConceptIDFamily(family, c);
			}
		}
	}
	
	private void generateLabTests(List<LabTest> labTests){
		List<LabTest> extendedLabTest = new ArrayList<LabTest>();
		for(LabTest lt:labTests){
			Concept concept = lt.getOrder().getConcept();
			if(concept.getConceptClass().getName().equals("LabSet")){
				for (ConceptAnswer ca : concept.getAnswers()) {
					Concept c = ca.getAnswerConcept();
					LabTest nlt = new LabTest();
					nlt.setAcceptDate(lt.getAcceptDate());					
					nlt.setLab(lt.getLab());
					nlt.setLabTestId(lt.getLabTestId());
					nlt.setLabTestStatus(lt.getLabTestStatus());
					extendedLabTest.add(nlt);
				}

				for (ConceptSet cs : concept.getConceptSets()) {
					Concept c = cs.getConcept();
					LabTest nlt = new LabTest();
					nlt.setAcceptDate(lt.getAcceptDate());
					nlt.setLab(lt.getLab());
					nlt.setLabTestId(lt.getLabTestId());
					nlt.setLabTestStatus(lt.getLabTestStatus());
					extendedLabTest.add(nlt);
				}
			}
		}
		labTests.addAll(extendedLabTest);
	}
}
